package com.tfswx.jcyw.print.log;

import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.helpers.MessageFormatter;

import java.util.Date;

/**
 * @author 张述江
 * @date 2023/12/18
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class LogObj extends LogEvent {
    private Date date;
    private String className;
    private String methodName;
    private int lineNumber;
    private String threadName;
    private String logLevel;
    private String message;
    private Object[] params;
    private Throwable throwable;
    private String formattedMessage;


    public Throwable getThrowable() {
        refresh();
        return throwable;
    }


    public Object[] getParams() {
        refresh();
        return params;
    }


    public String getFormattedMessage() {
        refresh();
        if (StringUtils.isBlank(formattedMessage)) {
            formattedMessage = MessageFormatter.arrayFormat(message, params).getMessage();
        }
        return formattedMessage;
    }

    private void refresh() {
        if (throwable == null) {
            this.throwable = extractThrowableAnRearrangeArguments(params);
        }
    }

    private Throwable extractThrowableAnRearrangeArguments(Object[] argArray) {
        Throwable throwable = extractThrowable(params);
        if (throwable != null) {
            params = trimmedCopy(argArray);
        }
        return throwable;
    }

    private Object[] trimmedCopy(Object[] argArray) {
        if (argArray == null || argArray.length == 0) {
            throw new IllegalStateException("non-sensical empty or null argument array");
        }
        final int trimemdLen = argArray.length - 1;
        Object[] trimmed = new Object[trimemdLen];
        System.arraycopy(argArray, 0, trimmed, 0, trimemdLen);
        return trimmed;
    }

    private Throwable extractThrowable(Object[] argArray) {
        if (argArray == null || argArray.length == 0) {
            return null;
        }

        final Object lastEntry = argArray[argArray.length - 1];
        if (lastEntry instanceof Throwable) {
            return (Throwable) lastEntry;
        }
        return null;
    }
}
